﻿
namespace Behemoth.SharePoint.Utilities {

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;

    using Microsoft.SharePoint;
    using Behemoth.SharePoint;

	public partial class Customization {

		public void FixCustomProperties(SPWeb web) {
			foreach (CustomizationArrayOfProperty array in this.ArrayOfProperty) {
				string fieldName = array.FieldName;
                SPField field = null;
                bool success = web.Fields.TryGetField(fieldName, out field);
                if (success && field != null) {
					foreach (CustomizationArrayOfPropertyProperty prop in array.Property) {
						string name = prop.Name;
						object val = prop.Value;
						try {
							field.SetCustomProperty(name, val);
							field.Update( true );
						} catch (Exception ex) {
							throw new Exception(string.Format("Error while trying to set custom property '{0}' in field '{1}'. Error was: {2}.", name, fieldName, ex.Message), ex);
						} // try
					} // foreach prop
				} // if
			} // foreach array
		}

        public static string GetListSchemaFilePath(SPFeature feature, string listName) {
            string dir = feature.GetFeatureFilePath();
            dir = Path.Combine(dir, listName);
            dir = Path.Combine(dir, "schema.xml");
            return dir;
        }

        public static void FixCustomPropertyOnListSchema(SPWeb targetWeb, SPFeature feature, string listName) {
			string filePath = GetListSchemaFilePath( feature, listName );
			FixCustomPropertyOnListSchema( targetWeb, filePath );
		}
		public static void FixCustomPropertyOnListSchema( SPWeb targetWeb, string filePath ) {
			if (!File.Exists( filePath ))
				throw new FileNotFoundException(string.Format( "DoCustomPropertyFixOnListSchema could not find the lsit schema at specified location '{0}'.", filePath ));
			XmlDocument xDoc = new XmlDocument();
			xDoc.Load( filePath );

			XmlElement listElem = xDoc.SelectSingleNode("//List") as XmlElement;
			string listTitle = listElem.GetAttribute( "Title" );
			if (string.IsNullOrEmpty( listTitle ))
				throw new Exception( "Failed ot get the list title from schema. " );

			/* turns out, also useless
			string listName = listElem.GetAttribute("Name");
			if (string.IsNullOrEmpty( listName ))
				throw new Exception( "Failed ot get the list name from schema. " );
			 */


        /* in this case the ID is useless to us because it refers to the id for the template not the instance
        string listId = listElem.GetAttribute("Id");
        if (string.IsNullOrEmpty(listId))
            listId = listElem.GetAttribute( "ID" );
        if (string.IsNullOrEmpty( listId ))
            throw new Exception("Failed ot get the list ID from schema. ");
        */

        // TODO it is possible that this may want the display name - yuk!
        SPList list = null; 
        try {
            list = targetWeb.Lists[listTitle];
        } catch {
            throw new Exception(string.Format("Failed to get the list with title '{0}' from the specified web.", listTitle));
        }
	
        XmlSerializer ser = new XmlSerializer( typeof( Customization ) );

        XmlNodeList fieldNodes = xDoc.SelectNodes( "//List/MetaData/Fields/Field" );
        foreach (XmlNode fieldNode in fieldNodes) {

            XmlElement fieldElem = fieldNode as XmlElement;
            string fieldId = fieldElem.GetAttribute( "ID" );
            if (string.IsNullOrEmpty(fieldId))
                fieldId = fieldElem.GetAttribute( "Id" );

            //if (string.IsNullOrEmpty( fieldId )) {
            //  throw new Exception( "Failed to get the fieldName ID." );
            // above line commented: just skip the fieldName, computed fields don't have any ID attribute

            string fieldName = string.Empty, staticName, displayName;
            try { // useful for producing error messages if nothing else
                fieldName = fieldElem.GetAttribute( "Name" );
                staticName = fieldElem.GetAttribute( "StaticName" );
                displayName = fieldElem.GetAttribute( "DisplayName" );
            } catch {
            }

            if (!string.IsNullOrEmpty( fieldId )) {
                SPField field = list.Fields[new Guid( fieldId )];

                XmlNode customizationNode = fieldElem.SelectSingleNode( "./Customization" );
                if (customizationNode != null) {
                    XmlDocument custDoc = GetCustomizationDocument( customizationNode, fieldName );
                    // Deserialize it
                    XmlTextReader reader = new XmlTextReader( new StringReader( custDoc.OuterXml ) ); // probably a very sloppy way to handle this...
                    object o = ser.Deserialize( reader );
                    Customization cust = o as Customization;
                    CustomizationArrayOfProperty propArray = cust.ArrayOfProperty[0];
                    bool save = false;
                    foreach (CustomizationArrayOfPropertyProperty prop in propArray.Property) {
                        string propName = prop.Name;
                        object propValue = prop.Value;
                        field.SetCustomProperty( propName, propValue );
                        save = true;
                    }
                    if (save)
                        field.Update();
                } // if (customizationNode != null)
            } // if (!string.IsNullOrEmpty( fieldId )) {

        } // foreach
			
    }
        // TODO there has to be a better way to do this :-S
        // prime a new document to be converted to an object
        private static XmlDocument GetCustomizationDocument(XmlNode customizationNode, string fieldName) {
            XmlDocument custDoc = new XmlDocument();

            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" ?>\r\n");
            string xml = customizationNode.OuterXml;
            xml = xml.Replace("<Customization>", "<Customization xmlns=\"http://Behemoth.com/SharePoint/CustomProperties\">");
            sb.Append(xml);
            custDoc.LoadXml(sb.ToString());
            XmlNamespaceManager nameMgr = new XmlNamespaceManager(custDoc.NameTable);
            nameMgr.AddNamespace("tns", "http://Behemoth.com/SharePoint/CustomProperties");

            // add the fieldName attrib
            XmlNode arrayNode = custDoc.SelectSingleNode("//tns:Customization/tns:ArrayOfProperty", nameMgr);

            XmlElement array = arrayNode as XmlElement;
            array.SetAttribute("FieldName", fieldName);
            /*
            XmlAttribute fieldNameAttrib = custDoc.CreateAttribute( "FieldName" );
            fieldNameAttrib.Value = fieldName;
            array.Attributes.Append( fieldNameAttrib );
             */

            return custDoc;
        }

	} // class

} // namespace